<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  闭包是什么？

  1.犀牛书：函数变量可以保存在函数作用域内

  2.高级程序设计：
  闭包是指有权访问另一个函数作用域中的变量的函数（函数没导出）

  3.你不知道的JavaScript：
  当函数可以记住并访问所在的词法作用域时，就产生了了闭包，
  即使函数是在当前词法作用域之外执行

  4.MDN：
  一个函数和对其周围状态（词法环境）的引用捆绑在一起，
  这样的组合就是闭包(closure)；

  5.自我归纳：1.当函数的执行，导致函数被定义，并抛出；
  2.闭包和函数的定义有关



  <script>
    // 犀牛书的说法，显然太宽泛了
    // function foo() {
    //   var n = 0;
    // }
    // console.log(n);

    /* 
    function foo() {
      var n = 0;

      return function bar() {
        console.log(n);
      }
      // bar()
    }
    foo()() */

    // 面试题1
    /* 
    function foo(fn) {
      var n = 0;
      // 只是函数的执行没有定义，所以不会产生闭包
      fn()
    }

    function test() {
      console.log(n);
    }
    foo(test)
 */

    // 闭包的几种形式
    // 1. 函数返回值是函数
    /* function foo() {
      var n = 0
      return function() {
        console.log(n);
      }
    }
    foo() */

    // 2.返回的变量是函数
    /* function foo() {
      var n = function() {}
      return n
    }
    foo()() */

    // 3. 全局变量定义的闭包
    /* var outter;
    function foo() {
      var a = 10;
      outter = function() {
        console.log(a);
      }
    }
    foo()
    outter()
 */

    // 4. 函数的参数方式
    /* var inner = function(fn) {
      console.log(fn());
    }

    function foo() {
      var b = 'local';
      var n = function() {
        return b;
      }
      inner(n)
    }
    foo() */

    // 5.循环赋值问题
    // 通过嵌套一层闭包解决问题
    /*     
        function foo() {
          var arr = []
          for (var i = 0;i<10;i++) {
            arr[i] = (function(j) {
              return function() {
                console.log(j);
              }
            })(i)
          }
          return arr
        }

        var bar = foo()
        for (var j = 0;j<10;j++) {
          bar[j]()
        }
     */

    // 6.累加器
    /* 
    var add = (function() {
      let count = 0
      return function() {
        return ++count
      }
    })()

    console.log(add());
    console.log(add());
    console.log(add());
 */

    // 面试题2
    function fun(n, o) {
      console.log(o);
      return {
        fun: function(m) {
          return fun(m, n)
        }
      }
    }

    // var a = fun(0); // undefined
    // a.fun(1); // 0
    // a.fun(2); // 0
    // a.fun(3); // 0

    // var b = fun(0)  // undefined
    //     .fun(1)  // 0
    //     .fun(2)  // 1
    //     .fun(3)  // 2  
    
    var c = fun(0).fun(1); // undefined 0
    console.log(c);
    c.fun(2);  // 1
    c.fun(3); // 1



  </script>
</body>

</html>